package cloud.lysky.java.on.concurrent.lock.stampedlock;

import java.util.concurrent.locks.StampedLock;

/**
 * @author luoly
 * @describe StampedLock使用示例
 * @date 2023-04-30 21:41
 **/
// 下面是一个使用StampedLock实现的线程安全的Point类，它表示一个二维坐标系中的一个点。
public class PointDemo {
    private double x, y;
    private final StampedLock s1 = new StampedLock();

    // 获取当前位置的x坐标
    public double getX() {
        // 乐观读
        long stamp = s1.tryOptimisticRead();
        double currentX = x;
        // 检查乐观读锁后是否有其他写锁发生
        if (!s1.validate(stamp)) {
            // 升级为悲观读锁
            stamp = s1.readLock();
            try {
                currentX = x;
            } finally {
                // 释放悲观读锁
                s1.unlockRead(stamp);
            }
        }
        return currentX;
    }
    // 获取当前位置的y坐标
    public double getY() {
        // 乐观读
        long stamp = s1.tryOptimisticRead();
        double currentY = y;
        // 检查乐观读锁后是否有其他写锁发生
        if (!s1.validate(stamp)) {
            // 升级为悲观读锁
            stamp = s1.readLock();
            try {
                currentY = y;
            } finally {
                // 释放悲观读锁
                s1.unlockRead(stamp);
            }
        }
        return currentY;
    }

    // 移动点到新的位置
    public void move(double deltaX, double deltaY) {
        // 获取写锁
        long stamp = s1.writeLock();
        try {
            x += deltaX;
            y += deltaY;
        } finally {
            // 释放写锁
            s1.unlockWrite(stamp);
        }
    }

    public static void main(String[] args) {
        PointDemo point = new PointDemo();
        // 开启一个线程写
        new Thread(() -> {
            System.out.println("写线程启动");
            point.move(1, 2);
            try {
                Thread.sleep(3000);
                System.out.println("写线程结束");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }).start();
        // 开启多个线程读
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                System.out.println("x: " + point.getX() + ", y: " + point.getY());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }).start();
        }
    }
}
